Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable stacking of windows #344

Closed
wants to merge 8 commits into from
Closed

Conversation

unrevre
Copy link

@unrevre unrevre commented Dec 15, 2019

.. by adding new splitting direction: along 'z' axis. child nodes have the same location and size, and automatically inherit this split type so that all child nodes of the (sub)-tree stack. above/below selectors select the next/previous window if the coordinates and sizes match.

i've been using this for about 2 months and things seems to work as expected, though i have not tested everything extensively. it is built entirely on the existing machinery. would you consider this as a solution to #203 (and others)?

additional split mode, allowing new windows to be inserted above the
selected window.
subsequent splittings take on the same window size.
'below', in addition to 'above'. represents stacking order.
require all nodes on paths to lowest common ancestor of current +
prev/next nodes to be z-split nodes.
@koekeishiya
Copy link
Owner

I sort of see how this implementation would work, but at first glance there appears to be some issues that remain unresolved.

Using window dimensions to decide whether the prev/next matches is not really reliable due to min/max size constraints, and incremental constraints (e.g Terminal.app).

What's natural behaviour if you have A&B(stack) | C and you decide to do a horizontal split on A. Do both A&B get split and remain stacked? If so, I think that makes bsp-structure (at least the way it is used thus far) not appropriate, as it looks something like this before the insertion:

     *
    / \
   *   C
  / \
 A   B

Now splitting A should cause both A and B to be split. Now if I read the current structure correctly, it is also legal to do a z-split on A, which will lead to the following tree:

      *
     / \
    *   C
   / \
  *   B
 / \
A  E

where the window A, E and B (with their respective parents) all represent the same region. This will interact poorly with the existing zoom-parent functionality etc.

Should it be possible to perform operations that apply to an entire stack of window, e.g I want to warp both A&B simultaneously, or even just swap positions of the stack with some other window.

I think this is an interesting take on this problem, but I'm not sure it is the way to go. That said, I expect that most of these questions that I have raised are fairly trivial to solve, but these are my thoughts so far.

@unrevre
Copy link
Author

unrevre commented Dec 16, 2019

I sort of see how this implementation would work, but at first glance there appears to be some issues that remain unresolved.

Using window dimensions to decide whether the prev/next matches is not really reliable due to min/max size constraints, and incremental constraints (e.g Terminal.app).

right. i was lazy here.. i guess the correct approach would be to find the prev/next node and check that the split type is 'z' for the parent node?

What's natural behaviour if you have A&B(stack) | C and you decide to do a horizontal split on A. Do both A&B get split and remain stacked? If so, I think that makes bsp-structure (at least the way it is used thus far) not appropriate, as it looks something like this before the insertion:

     *
    / \
   *   C
  / \
 A   B

Now splitting A should cause both A and B to be split. Now if I read the current structure correctly, it is also legal to do a z-split on A, which will lead to the following tree:

      *
     / \
    *   C
   / \
  *   B
 / \
A  E

where the window A, E and B (with their respective parents) all represent the same region. This will interact poorly with the existing zoom-parent functionality etc.

sorry, i think i was not clear with what i meant by 'inheriting the split type'. it happens when E is created and requires that the parent node is a z-split node. by splitting A, the split type of the parent node is set to 'horizontal', so E does not inherit the z-split type and does not stack with A. window B is also not affected by the creation of E, so the result is that A and E are side-by-side and stacked with B, with the combined size of A and E being that of B (and A before the split).

this does lead to some fun and maybe not very bsp-like layouts, but personally i found it natural (any node is allowed to split in any direction) and did not want to redefine this behaviour. i do recognise that stacking is somewhat special, so i'm happy to change it to whatever you think is more reasonable.

Should it be possible to perform operations that apply to an entire stack of window, e.g I want to warp both A&B simultaneously, or even just swap positions of the stack with some other window.

this is not possible with this patch (currently). i believe it is also not currently possible to warp or swap an entire subtree, but if it is, then this would come (almost) for free.

I think this is an interesting take on this problem, but I'm not sure it is the way to go. That said, I expect that most of these questions that I have raised are fairly trivial to solve, but these are my thoughts so far.

thanks for the comments (: i'll try to fix the above/below selectors first.

@jmpohl
Copy link

jmpohl commented Jan 31, 2020

Any word on this? Really excited to use yabai, but my workflow heavily uses the stacking features of chunkwm...

Is there anything I can do to help?

@unrevre
Copy link
Author

unrevre commented Feb 2, 2020

i've fixed the above/below selectors to work reliably by checking the tree structure. i believe the remaining outstanding item is the ability to act on entire stacks of windows, which should not be too difficult (i've neglected it so far simply because i don't use it).

@koekeishiya if you have any further thoughts, questions, or comments, just let me know (:

@dominiklohmann
Copy link
Collaborator

From a design perspective, it doesn't quite make sense to have stacked windows occupy separate nodes in the tree structure, does it?

@unrevre
Copy link
Author

unrevre commented Feb 3, 2020

From a design perspective, it doesn't quite make sense to have stacked windows occupy separate nodes in the tree structure, does it?

@dominiklohmann the idea is that you can implement stacking by extending the tree structure from 2-d to 3-d. effectively you treat each window as having a "volume" of (x, y, 0) -> then splitting in "z" gives you two stacked windows. personally, i felt it does make sense this way (in 3-d).

to be clear, i'm not saying this is the best way to do it; i can understand if you don't agree with this design. i just thought i'd share this since it required minimal change to the internals (so i think i didn't break anything).

again, if there's any changes or additions you would like to see before considering to accept this, just let me know (:

@dominiklohmann
Copy link
Collaborator

It's not my choice to make whether this gets merged.

I'd like to see this happen—don't get me wrong—but I don't think this implementation is very intuitive. Some users already have trouble with the 2-dimensional tree, and making it 3-dimensional makes it even harder to reason about tree manipulation (i.e., rotate, swap, warp, mouse actions).

Instead, I think the 2-dimensional tree should be kept, and nodes should be changed to be able to hold any amount of windows instead of being required to hold exactly one. In a way, this decouples the concepts of node and window. Windows in a node should be ordered by most recently raised.

I personally think that being able to intuitively reason about tree manipulations is one of the major features of yabai.

@unrevre
Copy link
Author

unrevre commented Feb 3, 2020

I'd like to see this happen—don't get me wrong—but I don't think this implementation is very intuitive. Some users already have trouble with the 2-dimensional tree, and making it 3-dimensional makes it even harder to reason about tree manipulation (i.e., rotate, swap, warp, mouse actions).

the tree is of course still a bsp tree, so it's exactly the same as before; what i had meant was that the space it represents is now a "3-d" space, sorry!

I personally think that being able to intuitively reason about tree manipulations is one of the major features of yabai.

sure, i agree. for reference, this is the current behaviour, without doing anything special:

  • rotate: given how this is implemented in yabai, rotating the tree will move the entire stack as a whole
  • swap: swaps any two windows (can swap windows into/out of stacks)
  • warp: warping into a window splits the window, so warping into a window that is part of a stack adds it to the stack
  • mouse actions: unfortunately, i have never used them...

@kvndrsslr
Copy link

I am just making the move to yabai from manually adjusting my windows using Phoenix. First of all, thank you all for your investment in this great project!

Since I am used to stacking windows I have tested this feature and I really like it. However, I found one thing confusing. I have a horizontal split and on the left side I have a z-split of two windows. The single window on the right is focused. Moving north, east or south will always toggle between the two visible windows. Moving west twice will show the previously hidden window. So far so good, but once I have switched windows within the z-split, moving north, west or south will only toggle between the two windows in the z-split.

It seems like the initial switching of windows along the z-axis switches the plane in which we interpret the compass directions. I would prefer if additionally to the normal compass directions you add another two directions (up, down) to really make this 3D metaphor work. If we are not in a z-split, then moving along these directions should have no effect. I am not familiar with the implementation details of the bsp so I do not know if this makes sense, just wanted to add my 5c.

@nkezhaya
Copy link

@koekeishiya any thoughts on this? It'd be great to see this merged

@koekeishiya
Copy link
Owner

Same opinion as before. While this implementation may work, it does not make sense technically to me, that nodes are duplicated when they represent the same region.

@koekeishiya
Copy link
Owner

That said, I am now at a stage where I probably will start to look into implementing support for stacking windows soon. I am pretty comfortable with the current complexity and robustness of the feature set at this point.

@kcrwfrd
Copy link

kcrwfrd commented Jun 15, 2020

FWIW I like the idea of introducing it as a type of split and maintaining it in a BSP, slightly decoupling "node" and "window" like @dominiklohmann observed.

Or, what if they were decoupled even further so that each node had a collection of windows? And behavior like warping or swapping is applied to the node that a window belongs to, rather than specifically that window. Idk if this would introduce problems elsewhere, but it seems like this might be how I3 is implemented.

I think you commented somewhere that to implement this you would want to be able to surface UI for good UX (like i3 does), and that presents a problem in MacOS. FWIW, I've been using toggle parent zoom + floating a window to accomplish the desired stacked window positioning, with native CMD + ` or CMD + TAB to cycle through the windows. So even if this can't be implemented with the ideal UI/UX, as long as it doesn't affect other use cases it would still be extremely useful for me.

I was still using chunkwm for the zoom/float hack, but if you're considering how to implement I would be happy to switch to @unrevre's build to test and start thinking about how a stacking feature would affect everything @koekeishiya.

@koekeishiya
Copy link
Owner

what if they were decoupled even further so that each node had a collection of windows? And behavior like warping or swapping is applied to the node that a window belongs to, rather than specifically that window.

This is more or less what I will be doing, yes. I have most of it figured out, just haven't actually started doing it yet.

@koekeishiya
Copy link
Owner

Closing this as #203 is in progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants